package core

import "craft/core/token"

type state int

// 有限状态机的状态
const (
	SInitial state = iota
	SID            // 原始状态
	SNum
	SGT
	SGE
	SIDInt1
	SIDInt2
	SIDInt3
	SAssignment

	SPlus
	SMinus
	SStar
	SSlash
)

// LexicalAnalyzer 词法分析器
type LexicalAnalyzer struct {
	_state  state
	_tokens token.Tokens
	_token  *token.Token
}

// Analyze 传入语句字符串，返回 token 列表
func (l *LexicalAnalyzer) Analyze(sentence string) token.Tokens {
	l._tokens = make(token.Tokens, 0, 8)
	l._state = SInitial
	l._token = &token.Token{}

	for _, _char := range sentence {

		switch l._state {
		case SInitial:
			l.initial(_char)

		case SID:
			if isIdentify(_char) {
				l._token.Content += string(_char)
			} else {
				l.initial(_char)
			}

		case SIDInt1:
			if isIdentify(_char) {
				l._token.Content += string(_char)
				if _char == 'n' {
					l._state = SIDInt2
				}
			} else {
				l.initial(_char)
			}
		case SIDInt2:
			if isIdentify(_char) {
				l._token.Content += string(_char)
				if _char == 't' {
					l._state = SIDInt3
				}
			} else {
				l.initial(_char)
			}
		case SIDInt3:
			if isIdentify(_char) {
				l._token.Content += string(_char)
				l._state = SID
			} else {
				l._token.Type = token.Int
				l.initial(_char)
			}

		case SPlus:
		case SMinus:
		case SStar:
		case SSlash:
		case SAssignment:
			l.initial(_char)

		case SNum:
			if isNum(_char) {
				l._token.Content += string(_char)
			} else {
				l.initial(_char)
			}

		case SGT:
			if _char == '=' {
				l._token.Content += string(_char)
				l._state = SGE
			} else {
				l.initial(_char)
			}
			break
		case SGE:
			l.initial(_char)
			break
		}
	}

	l.initial(' ')

	return l._tokens
}

func (l *LexicalAnalyzer) initial(c rune) {
	if len(l._token.Content) > 0 {
		l._tokens = append(l._tokens, *l._token)
	}

	l._token = &token.Token{100, ""}
	l._state = SInitial

	// 状态机
	if isNum(c) {
		l._token.Type = token.IntLiteral
		l._state = SNum
	} else if isAlpha(c) {
		if c == 'i' {
			l._state = SIDInt1
		} else {
			l._state = SID
		}
		l._token.Type = token.Identifier

	} else if c == '>' {
		l._token.Type = token.GT
		l._state = SGT
	} else if c == '=' {
		l._token.Type = token.Assignment
		l._state = SAssignment
	} else if c == '+' {
		l._token.Type = token.Plus
		l._state = SAssignment
	} else if c == '-' {
		l._token.Type = token.Minus
		l._state = SAssignment
	} else if c == '*' {
		l._token.Type = token.Star
		l._state = SAssignment
	} else if c == '/' {
		l._token.Type = token.Slash
		l._state = SAssignment
	}

	if l._state != SInitial {
		l._token.Content += string(c)
	}
}

func isNum(c rune) bool {
	if c >= '0' && c <= '9' {
		return true
	}
	return false
}

func isAlpha(c rune) bool {
	if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' {
		return true
	}
	return false
}

func isIdentify(c rune) bool {
	return isAlpha(c) || isNum(c)
}
